import { deepMerge } from '@/assets/js/utils.js'
import { ElMessage } from 'element-plus'

const DEFAULT_CONFIG = {
  minRatio: 0.1, // 最小
  maxRatio: 4, // 最大缩放
  theme: 'dark', // 主题
  nodeSize:[ // 节点大小
    {r:70,fontSize:23},
    {r:50,fontSize:20},
    {r:30,fontSize:17}
  ],
  handleClick:()=>{} // 点击事件
}

export default class CreateKnowledgeGraph {
  constructor(options) {
    const {data,originalData, rootId, d3, config={}} = options
    // 获取参数
    this.options = options
    // 获取配置
    this.config = deepMerge(JSON.parse(JSON.stringify(DEFAULT_CONFIG)),config)
    // 获取d3实例
    this.d3 = d3
    // 获取数据
    this.data = data
    // 获取原始数据
    this.originalData = JSON.parse(JSON.stringify(originalData))
    // dom信息
    this.domInfo={
      rootId, // domId
      nativeRootEl:'' // dom元素
    }
    // 图谱信息
    this.graphInfo = {
      showGraphMode: '', // 当前显示的图谱模式实例
      collectionSvg: '', // 根svg
      collectionZoom: '', //缩放对象
      chartWidth: 0, // 图谱宽度
      chartHeight: 0 // 图谱高度
    }
    // 初始化
    this.init()
  }

  // 初始化
  init() {
    // dom元素
    this.domInfo.nativeRootEl = document.querySelector(`#${this.domInfo.rootId}`)
    // d3元素
    let rootEl = this.d3.select(`#${this.domInfo.rootId}`)
    rootEl.html('')
    // 保存宽度
    this.graphInfo.chartWidth = rootEl.node().getBoundingClientRect().width
    // 保存高度
    this.graphInfo.chartHeight = rootEl.node().getBoundingClientRect().height
    // 创建SVG根元素
    this.graphInfo.collectionSvg = rootEl.append('svg')
      .attr('xmlns', 'http://www.w3.org/2000/svg')
      .attr('viewBox', `0 0 ${this.graphInfo.chartWidth} ${this.graphInfo.chartHeight}`)
      .attr('xmlns:xlink', 'http://www.w3.org/1999/xlink')
      .attr('width', '100%')
      .attr('height', '100%')
      .attr('id','d_collection_svg')
    // 创建缩放组
    this.graphInfo.collectionZoom = this.graphInfo.collectionSvg
      .append('g')
      .attr('id','d_zoom_box')

    // 初始化主题
    this.changeTheme()
    // 初始化缩放
    this.initScale()
  }

  // 切换主题
  changeTheme(theme) {
    if (theme) this.config.theme = theme
    this.graphInfo.collectionSvg
      .attr('class',`d_graph_base ${this.config.theme}`)
  }

  // 初始化缩放
  initScale() {
    this.zoom = this.d3
      .zoom()
      .scaleExtent([this.config.minRatio, this.config.maxRatio])
      .on('zoom', (e) => {
        this.graphInfo.collectionZoom.attr('transform', e.transform)
      })
    this.graphInfo.collectionSvg.call(this.zoom)
  }

  // 移动元素到屏幕中央
  setCenter(){
    this.autoZoom(
      this.zoom,//传入zoomObj
      'd_collection_svg',//<svg>的id
      'd_zoom_box',//<g>的id
      {
        row: 0,
        col: 0
      },//间隙参数（自定）
      800 // 补间时长（自定）
    )
  }

  // 保存
  save(callBack){
    callBack()
    ElMessage({
      message: '保存成功',
      type: 'success',
      offset: 100
    })
  }

  // 初始化隐藏状态
  changeHideType(type=[]){
    // 初始化
    [0,1,2].forEach((item)=>{
      // 隐藏节点
      this.d3.selectAll(`.d_groupsLevel_${item}`)
        .transition()
        .duration(500) // 动画持续时间，单位为毫秒
        .attr('opacity',type.includes(item)? 0.1:1)
    })
  }

  /**
   * 计算圆形轨迹
   * @param {Number} nodes 计算轨迹的节点列表
   * @param {Number} circleR 圆的半径
   * @param {Number} circleX 圆X坐标
   * @param {Number} circleY 圆Y坐标
   * @returns 角度
   */
  calculateCircular(nodes,circleR,circleX,circleY){
    // 一个元素占的角度
    let angle=360/Object.keys(nodes).length
    // 一个元素所占角度的弧度
    let radian=angle*Math.PI/180
    // 给节点赋值
    nodes.forEach((item,index)=>{
      item.x  = Math.sin((radian*index))* circleR + circleX
      item.y  = Math.cos((radian*index))* circleR + circleY
    })
  }

  /**
    @param zoomObj: 放缩对象，设置了放缩比率
    @param svgContainerId: 容器 <svg>
    @param svgBodyId: 画布 <g>
    @param marginParam: 间隙参数（自定义）
    @param duration: 补间时长
    @param scale: 缩放倍数
  **/
  autoZoom(zoomObj, svgContainerId, svgBodyId, marginParam, duration){
    // 拿外层SVG
    const svgContainer = document.querySelector(`#${svgContainerId}`)
    // 拿要居中的组
    const svgBody = this.d3.select(`#${svgBodyId}`)
    // 没拿到退出函数
    if (!svgContainer) {
      return
    }
    // 获取组的宽高
    const viewBox = svgBody.node().getBBox()
    // 获取外层SVG的宽高
    const containerWidth = svgContainer.clientWidth
    const containerHeight = svgContainer.clientHeight

    const rowMargin = marginParam.row
    const colMargin = marginParam.col

    //计算放缩倍数
    const scale = Math.min((containerWidth - rowMargin) / viewBox.width, (containerHeight - colMargin) / viewBox.height)

    // 计算如果要居中，画布需要的偏移量
    const offsetX = (containerWidth - rowMargin) / 2 - (viewBox.x + viewBox.width / 2) * scale
    const offsetY = (containerHeight - colMargin) / 2 - (viewBox.y + viewBox.height / 2) * scale
    // d3.zoomIdentity:缩放参数，返回Transform{k:1,x:0,y:0}
    const t = this.d3.zoomIdentity.translate(offsetX + rowMargin / 2, offsetY).scale(scale)
    // 计算完毕得到放缩参数t，<svg>标签调用zoomObj和计算好的t
    this.d3.select(`#${svgContainerId}`).transition().duration(duration).call(zoomObj.transform, t)
  }
}
